// TextDetector.cpp: implementation of the CTextDetector class.
//
//////////////////////////////////////////////////////////////////////

#include "ASample.h"
#include "AClassifier.h"
#include "CascadeClassifier.h"
#include "ItgImage.h"
#include "ObjectDetector.h"


//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CObjectDetector::CObjectDetector()
{
	m_pcClassifier = new CCascadeClassifier();

	pimage_org_grey = NULL;
	pimage_org_color = NULL;
}

void CObjectDetector::Free(void)
{
	if (m_pcClassifier != NULL)
		delete m_pcClassifier;
	m_pcClassifier = NULL;
}

CObjectDetector::~CObjectDetector()
{
	Free();
}

void CObjectDetector::Empty(void)
{
	if (pimage_org_grey != NULL)
		delete pimage_org_grey;
	pimage_org_grey = NULL;

	if (pimage_org_color != NULL)
		delete pimage_org_color;
	pimage_org_color = NULL;
}


//////////////////////////////////////////////////////////////////////
bool CObjectDetector::LoadClassifiers(const char *strFileName)
{
	return m_pcClassifier->LoadFromFile(strFileName);
}

int CObjectDetector::MergeTextRects(vrect &vRects, vfloat &vWeights)
{
	int nRects = vRects.size();
	uchar *pbFlags = new uchar[nRects];
	memset(pbFlags, 0, nRects);

	int i;
	for (i = 0; i < nRects; i++)
	{
		if (vWeights[i] < 0.95) pbFlags[i] = 1;
	}

	vrect vr, vrc;
	vfloat vw, vwc;
	for (i = 0; i < nRects; i++)
	{
		if (pbFlags[i]) continue;
		vrc.resize(0);
		vwc.resize(0);
		int k = i;
		vrc.push_back(vRects[k]);
		vwc.push_back(vWeights[k]);
		pbFlags[k] = 1;

		int m;
		do
		{
			m = vrc.size();
			
			for (int j = i+1; j < nRects; j++)
			{
				if (pbFlags[j]) continue;
				for (int n = 0; n < vrc.size(); n++)
				{
					irmm_Rect r = vrc[n] & vRects[j];
					int arear = r.Width() * r.Height();
					int areaj = vRects[j].Width() * vRects[j].Height();
					float ratio = (float)arear / areaj;
					float th = (float)((r.Height() > r.Width())?0.2:0.2);
					if ( ratio > th)
					{
						vrc.push_back(vRects[j]);
						vwc.push_back(vWeights[j]);
						pbFlags[j] = 1;
						break;
					}
				}
			}
		} while (m < vrc.size() );
//		if (k == i) continue;  // only one response

		// join intersected rects together
		float w = 0;
		int nc = vrc.size();
		int jmax=0;
		irmm_Rect rect = vrc[0];
		w = 1-vwc[0];
		for (int j = 1; j < nc; j++)
		{
			rect.UnionRect(rect, vrc[j]);
			w *= (1-vwc[j]);
		}
		rect.NormalizeRect();
		vr.push_back(rect);
		vw.push_back(1-w);
	}
	delete pbFlags;
	vRects = vr;
	vWeights = vw;

	return vRects.size();
}

int CObjectDetector::MergeFaceRects(vrect &vRects, vfloat &vWeights)
{
	int nRects = vRects.size();
	uchar *pbFlags = new uchar[nRects];
	memset(pbFlags, 0, nRects);

	vrect vr, vrc;
	vfloat vw, vwc;
	int i, j;
	for (i = 0; i < nRects; i++)
	{
		if (pbFlags[i]) continue;
		vrc.resize(0);
		vwc.resize(0);
		int k = i;
		vrc.push_back(vRects[k]);
		vwc.push_back(vWeights[k]);
		pbFlags[k] = 1;

		for (j = i+1; j < nRects; j++)
		{
			if (pbFlags[j]) continue;
			irmm_Rect r = vRects[k] & vRects[j];
			int arear = r.Area();
			int areaj = vRects[j].Area();
			if ( (float)arear / areaj > 0.5)
			{
				k = j;
				vrc.push_back(vRects[k]);
				vwc.push_back(vWeights[k]);
				pbFlags[k] = 1;
			}
		}
//		if (k == i) continue;  // only one response

		// Find maximum rect
		float w = 0;
		int nc = vrc.size();
		int jmax=0;
		for (j = 0; j < nc; j++)
		{
			if (w < vwc[j])
			{
				jmax = j;
				w = vwc[j];
			}
		}
		vr.push_back(vrc[jmax]);
		vw.push_back(w);
	}
	delete pbFlags;

	// if two rects are intersected
	nRects = vr.size();
	vrect::const_iterator vrit = vr.begin();
	vfloat::const_iterator vwit = vw.begin();
	for (i = 0; i < nRects; i++)
	{
		for (int j = i + 1; j < nRects; j++)
		{
			irmm_Rect r = vr[i] & vr[j];
			int arear = r.Area();
			if (arear > 0)
			{
				nRects --;
				if (vw[i]*vr[i].Width() >= vw[j]*vr[j].Width())
				{
					vr.erase(vrit+j); //&vr[j]
					vw.erase(vwit+j); //&vw[j]
					j --;
				}
				else
				{
					vr.erase(vrit+i);//&vr[i]
					vw.erase(vwit+i);
					i--;
					break;
				}
			}
		}
	}

	vRects = vr;
	vWeights = vw;

	return vRects.size();
}


/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
CTextDetector::CTextDetector()
:CObjectDetector()
{
}


CTextDetector::~CTextDetector()
{
	CObjectDetector::~CObjectDetector();
}

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CFaceDetector::CFaceDetector()
:CObjectDetector()
{
	m_pcClassifier = new CCascadeClassifier();
	m_harrs.Generate(32, 32);
}

CFaceDetector::~CFaceDetector()
{
	CObjectDetector::~CObjectDetector();
}

int CFaceDetector::PostProcessing(Raster<uchar> &src, vrect &vRects, vfloat &vWeights)
{
	MergeTextRects(vRects, vWeights);

	return vRects.size();
}

void CFaceDetector::LoadCVDetector(void)
{
	cv_face_detector.LoadFromFile("../Adaboost/SampleBase");
}
